package com.sjh.lib_update

import android.annotation.SuppressLint
import android.app.Application
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.BitmapFactory
import android.os.Build
import android.os.Environment
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.lifecycle.Lifecycle
import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.AppUtils
import com.blankj.utilcode.util.IntentUtils
import com.sjh.lib_update.ApkUtil.getApplicationVersionCode
import com.sjh.lib_update.ui.notification.SimpleNotificationBuilder
import com.sjh.baseutils.loading.LoadingType
import com.sjh.lib_update.InstallApp
import com.sjh.net.EasyClient
import com.sjh.net.Method
import com.sjh.net.download.downloadFile
import com.sjh.net.interceptor.HttpInfoCatchInterceptor
import com.sjh.net.request
import com.ylc.lib_update.R
import java.io.File
import java.lang.RuntimeException
import java.util.*

/**
 * 入口
 * @author ysj
 * @date 2020/6/24 16:24
 */
class AppUpDateManage private constructor(application: Application) {

    private var content: Context = application.applicationContext


    companion object {
        var downloadUrl = ""
        var checkUrl = ""
        //是否外部实现UI
        var isCustomUI = false
        //是否显示通知
        var isShowNotify = true
        //是否下载完后立即安装
        var isInstallApp = true

        //通知图标
        var notificationIcon = R.drawable.ic_launcher

        @SuppressLint("StaticFieldLeak")
        private lateinit var appUpDateManage: AppUpDateManage

        /**
         * 初始化，在Application里初始化 否则会出现意想不到的异常
         * @param application
         */
        @Synchronized
        fun init(application: Application): AppUpDateManage {
            appUpDateManage =
                AppUpDateManage(application)
            return appUpDateManage
        }


        /**
         * 获取实例
         * @return AppUpDateManage
         */
        fun getInstance(): AppUpDateManage {
            if (!this::appUpDateManage.isInitialized) {
                throw RuntimeException("AppUpDateManage is not init")
            }
            return appUpDateManage
        }
    }

    /**
     * 检查是否有版本更新
     * @param mLifecycle 生命周期
     * @param preBlock
     * @param channel 渠道分支
     * @param isLoading 是否加载load对话框
     * @param isReturn 是否弹窗
     * @param compiler 如果弹窗，可以自己处理逻辑
     * @param showInstallDialog 自定义实现 UI
     * @param showUpdateDialog 自定义实现 UI
     */
    fun checkApk(
        mLifecycle: Lifecycle,
        preBlock: EasyClient<UpDateRequest<UpDataBean>>.() -> Unit = { appConfig(this) },
        mParams:Map<String,String>,
        isLoading: Boolean = true,
        isReturn: Boolean = true,
        compiler: ((apkInfoBean: UpDataBean) -> Unit)? = null,
        showUpdateDialog: ((file: File, apkInfoBean: UpDataBean) -> Unit?)? = null
    ) {
        request(
            preBlock = preBlock,
            options = {
                method = Method.POST
                lifecycle = mLifecycle
            },
            block = {
                url = checkUrl
                loading = if (isLoading) LoadingType.GENERAL else LoadingType.NONE
                headers = {}
                params = {
                    map(mParams)
                }
                onResult = { s: String, t: UpDateRequest<UpDataBean>, b: Boolean, _ ->
                    if (t.data != null) {
                        compiler?.invoke(t.data!!)
                        if (isReturn) {//当要弹窗的时候。处理逻辑
                            if (needUpdateApk(t.data!!)) {
                                val path =
                                    content.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.absolutePath + "" +
                                            "/app_${t.data!!.version}_${t.data!!.version_code}.apk"

                                val f = File(path)
                                //判断是否有历史安装包，如果有就删除
                                if (f.parentFile.exists()) {
                                    f.parentFile.listFiles { dir, name -> name.startsWith("app") }
                                        .forEach {
                                            it.delete()
                                        }
                                }
                                if (isCustomUI) {
                                    showUpdateDialog?.invoke(f, t.data!!)
                                }else{
                                    showDefUpdateDialog(f, t.data!!)
                                }
                            }
                        }
                    }
                }
            })
    }


    /**
     * app 的整体配置，如果某个模块需要单独的配置，可以参照着来
     * @param easyClient 网络请求客户端
     */
    private fun appConfig(easyClient: EasyClient<*>) {
        // fixme 具体项目时，这里应该使用多环境配置，需要考虑到测试环境、开发环境、预发布环境、正式环境
        easyClient.baseUrl =
            downloadUrl
        //easyClient.setDefaultHeaders(mapOf("appConfig1" to "1", "appConfig2" to "2"))
        easyClient.setDefaultInterceptors(arrayListOf(HttpInfoCatchInterceptor()))
    }


    /**
     * 判断是否需要更新app
     * @param apkInfoBean 应用信息
     */
    private fun needUpdateApk(apkInfoBean: UpDataBean) =
        getApplicationVersionCode(content) < apkInfoBean.version_code

    /**
     * 显示下载对话框
     * @param file 文件
     * @param apkInfoBean 应用信息
     */
    private fun showDefUpdateDialog(file: File, apkInfoBean: UpDataBean) {
        val message = buildString {
            appendln("新版本：${apkInfoBean.version}")
//            append("更新包大小：").appendln(getApkSize(apkInfoBean.size))
            appendln()
            appendln(apkInfoBean.desc)
        }
        AlertDialog.Builder(ActivityUtils.getTopActivity(),
            R.style.BDAlertDialog
        )
            .setTitle("发现新版本")
            .setCancelable(apkInfoBean.method == 0)
            .setMessage(message)
            .setNegativeButton(if(apkInfoBean.method ==0)"取消" else "", null)
            .setPositiveButton("下载更新") { dialog, which ->
                downloadApk(file, apkInfoBean.download_url)
            }
            .show()
    }


    /**
     * 下载apk
     * @param file 下载后的文件
     * @param url 下载地址，可以是相对地址，也可以是绝对地址
     * @param isShowNotify 是否显示通知
     * @param isInstallApp 下载完成后是否立即安装
     * @param onDownload 下载时的回调
     * @param onComplete 下载完成的回调
     */
    fun downloadApk(
        file: File,
        url: String,
        isShowNotify: Boolean = Companion.isShowNotify,
        isInstallApp: Boolean = Companion.isInstallApp,
        onDownload: ((progress: Long, length: Long) -> Unit)? = null,
        onComplete: ((File) -> Unit)? = null
    ) {
        val notifyId = Random().nextInt(65536)
        var builder: SimpleNotificationBuilder? = null
        var oldProcess = -1
        if (isShowNotify) {
            builder =
                SimpleNotificationBuilder(
                    content,
                    notificationIcon,
                    "正在更新(0%)",
                    ""
                )
            builder.setTicker("")
                .setLargeIcon(
                    BitmapFactory.decodeResource(
                        content.resources,
                        notificationIcon
                    )
                )
                .configureNotificationAsDefault()
                .setProgress(100, 0, false)
                .setAutoCancel(false)
                .setContentIntent(
                    PendingIntent.getActivity(
                        content,
                        0,
                        Intent(content, ActivityUtils.getTopActivity()::class.java),
                        0
                    )
                )
                .setDefaults(Notification.DEFAULT_LIGHTS) //设置通知的提醒方式： 呼吸灯
                .setPriority(NotificationCompat.PRIORITY_MAX) //设置通知的优先级：最大
                .send(notifyId)
        }
        val downloadUrl = if (url.startsWith("http", true)) url else (downloadUrl + url)
        downloadFile(downloadUrl, file, onDownload = { progress, length ->
            if (isShowNotify && builder != null) {
                val progress = (progress * 100 / length).toInt()
                if (progress == oldProcess) return@downloadFile
                oldProcess = progress
                builder!!.setContentTitle("正在更新($progress%)")
                    .setLargeIcon(
                        BitmapFactory.decodeResource(
                            content.resources,
                            notificationIcon
                        )
                    )
                    .setProgress(100, progress, false)
                    .send(notifyId)
//                println("进度：$progress%")
            }
            onDownload?.invoke(progress, length)
        }, onComplete = {
            onComplete?.invoke(file)
            if (isShowNotify && builder != null) {
                builder!!.setContentTitle("正在更新(100%)")
                    .setContentText("下载完成，点击安装")
                    .setTicker("下载完成，点击安装")
                    .setProgress(100, 100, false)
                    .setContentIntent(
                        PendingIntent.getActivity(
                            content,
                            0,
                            IntentUtils.getInstallAppIntent(file),
                            0
                        )
                    )
                    .setAutoCancel(true)
                    .send(notifyId)
            }
            if (isInstallApp) {
                AppUtils.installApp(file)

            }
        })
    }

}